package com.mdhw.config;

import com.alibaba.fastjson.JSON;
import com.mdhw.common.annotation.Log;
import com.mdhw.common.enums.StatusEnum;
import com.mdhw.system.entity.SysLog;
import com.mdhw.system.entity.SysUser;
import com.mdhw.system.service.SysLogService;
import com.mdhw.system.service.SysUserService;
import com.mdhw.utils.IpAddressUtil;
import com.mdhw.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
@Aspect
@Slf4j
 public class HttpLogAspect {
    String methodName;      // 方法名
    long startTime;         // 开始时间
    String response= "";      // 返回参数

    @Autowired
    private SysLogService service;
    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private HttpServletRequest request;
    /**
     * 定义一个切入点.
     * 解释下：
     *
     * ~ 第一个 * 代表任意修饰符及任意返回值.
     * ~ 第二个 * 定义在web包或者子包
     * ~ 第三个 * 任意方法
     * ~ .. 匹配任意数量的参数.
     */
    @Pointcut("@annotation( com.mdhw.common.annotation.Log)")
    public void aopPointCut() {
    }

    @Before("aopPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        methodName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        startTime = System.currentTimeMillis();
    }

    @After("aopPointCut()")
    public void doAfter() {
        long E_time = System.currentTimeMillis() - startTime;
        log.info("执行 " + methodName + " 耗时为：" + E_time + "ms");
    }

    @AfterReturning(returning = "object", pointcut = "aopPointCut()")
    public void doAfterReturning(Object object) {
        if(object != null){
            response = JSON.toJSONString(object);
        }
    }

    @Around("aopPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
        long beginTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long time = System.currentTimeMillis() - beginTime;
            // 保存日志
            saveLog(joinPoint, time);
            return result;
        } catch (Throwable e) {
            throw e;
        }
    }
    //保存日志
    private void saveLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLog sysLog = new SysLog();
        sysLog.setTime((int) time);
        Log logAnnotation = method.getAnnotation(Log.class);
        // 注解上的描述
        if (logAnnotation != null) {
            //模块名称
            sysLog.setModuleName(logAnnotation.module());
            //操作描述
            sysLog.setModuleValue(logAnnotation.value());
            log.info("模块名称:{}",logAnnotation.module());
            log.info("操作描述:{}",logAnnotation.value());
        }
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.info("方法名:{}",className+"."+methodName+"()");
        //方法名
        sysLog.setMethodName(className+"."+methodName+"()");
        // 请求的方法参数值
        Object[] args = joinPoint.getArgs();
        // 参数名数组
        String[] parameterNames = ((MethodSignature) signature).getParameterNames();
        // 构造参数组集合
        List<Object> argList = new ArrayList<>();
        for (Object arg : joinPoint.getArgs()) {
            // request/response无法使用toJSON
            if (arg instanceof HttpServletRequest) {
                argList.add("request");
            } else if (arg instanceof HttpServletResponse) {
                argList.add("response");
            } else if (arg instanceof MultipartFile) {
                argList.add("file");
            } else {
                argList.add(JSON.toJSON(arg));
            }
        }
        String token = JwtUtil.getRequestToken(request);
        String userId =  JwtUtil.parseToken(token);
        SysUser sysUser = sysUserService.getById(userId);
        //获取平台名字信息
        String systemName = sysUserService.findSystemNameByUserId(userId);
        log.info("当前用户:{},平台名称:{}",sysUser.getLoginName(),systemName);
        //sysLog.setCreateUser(sysUser != null ? sysUser.getName() : "");
        sysLog.setSystemName(systemName != null ? systemName : "");
        sysLog.setCreateDate(new Date());
        sysLog.setCreateUser(sysUser.getLoginName());
        sysLog.setStatus(StatusEnum.OK.getCode());
        sysLog.setParams(JSON.toJSONString(parameterNames)+":"+JSON.toJSONString(argList));
        log.info("方法({}) -> 参数:{} - {}", methodName, JSON.toJSONString(parameterNames), JSON.toJSONString(argList));
        // 获取request
        sysLog.setIp(IpAddressUtil.getRequestIp());
        log.info("IP:"+ IpAddressUtil.getRequestIp());
        sysLog.setResponse(response);
        log.info("response:{}",response);
        service.save(sysLog);
    }
}
